package roles

import (
	"fmt"
	"time"

	"gitee.com/cjianwen/go/demo/socks_v2/raft_demo/server/consts"
	"gitee.com/cjianwen/go/demo/socks_v2/raft_demo/server/global"
	"gitee.com/cjianwen/go/logs"
	"gitee.com/cjianwen/go/utils"
)

type leader struct {
	*roleState
	lastSendPingTime time.Time

	currAppendIdx    uint32
	trySendIdx       uint32
	step             byte
	lastSendDataTime time.Time
}

func (l *leader) Reset() {
	l.currAppendIdx = global.DataEntries.GetIndex()
	l.trySendIdx = l.currAppendIdx
	l.prot.SendPing(l.currAppendIdx) // 成为 leader 后， 马上发送 ping 消息，让其它 node 马上切换状态
	l.lastSendPingTime = time.Now()
	l.lastSendDataTime = l.lastSendPingTime

	// 测试代码
	logs.Println("添加五行测试数据")
	for i := 0; i < 5; i++ {
		str := fmt.Sprintf("测试一下添加五行数据 term = %d, sid = %d, dataid = %d", l.Term, global.ServerInfo.ServerId, l.dataId+1)
		logs.Printf("data = " + str)
		l.AddData(str)
	}
	logs.Printf("DataIndex = %d", global.DataEntries.GetIndex())

	for i := uint32(0); i < 5; i++ {
		data := global.DataEntries.GetEntryItem(i)
		if data != nil {
			logs.Printf("%d, prevTerm = %d, data = %#+v", i, global.DataEntries.GetEntryItemTerm(i-1), data)
		}
	}
}

func (l *leader) Run() error {
	if !global.NodeConns.ConnCountIsOK() {
		logs.Println("leader 的连接数不足，切换成为 Candidate, connCount = ", global.NodeConns.GetConnCount())
		l.becomeCandidate()
		return nil
	}

	if utils.TimePassed(&l.lastSendPingTime, consts.PingInterval) {
		l.prot.SendPing(l.currAppendIdx)
	}

	dataIdx := global.DataEntries.GetIndex()
	if l.trySendIdx < dataIdx {
		l.trySendIdx = dataIdx
		l.lastSendDataTime = time.Now()
		l.step = 1
		logs.Printf("SendAppend %d", l.trySendIdx)
		l.prot.SendAppend(l.trySendIdx - 1)
	} else if l.step > 0 {
		switch l.step {
		case 1: // 发送 append
			if global.CountIsAllOK(l.appendRespCount) {
				global.DataEntries.Commit(l.trySendIdx)
				l.lastSendDataTime = time.Now()
				l.prot.SendCommit(l.trySendIdx)
				l.step = 2 // 准备发送 commit
			} else if utils.TimePassed(&l.lastSendDataTime, consts.AppendTimeout) {
				l.prot.SendAppend(l.trySendIdx - 1) // 得时重发
			}

		case 2: // 发送 commit 并等待返回
			if global.CountIsAllOK(l.commitRespCount) {
				logs.Printf("(l *leader) Run: leader append 完成 %d -> %d", l.currAppendIdx, l.trySendIdx)
				l.currAppendIdx = l.trySendIdx
				l.step = 0 // 完成 append 操作
			} else if time.Since(l.lastSendDataTime).Milliseconds() >= consts.CommitTimeout {
				logs.Warn("(l *leader) Run: leader commit 超时重试: %d, %d", l.trySendIdx, l.commitRespCount)
				l.step = 1 // 超时回去重试
			}
		}
	}
	return nil
}
